#!/usr/bin/env python

__author__ = 'Emiliano Dalla Verde Marcozzi'
__version__ = '0.1'
__copyright__ = 'Licencia GPL v2'

import os
import psi
import pwd
import sys
import grp
import config
import optparse
import enumprocess

class processtool:
    """ Utility class to get info from the process.
    aka: pt (Argentina's ppl should understand the meaning from pt ;) ...
    me gaste che! aca se ve mau meno como se usa esta cosa :)
    
    In [1]: from process import process

    In [2]: pr = process()

    In [3]: type pr
    ------> type(pr)
    Out[3]: <type 'instance'>

    In [4]: pids = pr.getPids()

    In [5]: type pids
    ------> type(pids)
    Out[5]: <type 'list'>

    In [6]: pid = pids[-1]

    In [7]: pid
    Out[7]: 31806

    In [8]: pidMemoryInfo = pr.getProcessMemoryInfo(pid)

    In [9]: type pidMemoryInfo
    ------> type(pidMemoryInfo)
    Out[9]: <type 'dict'>
    
    # virtual and real memory process usage
    In [10]: pidMemoryInfo
    Out[10]: {'rm': 12558336L, 'vm': 97898496L} 

    In [11]: niceprint = " %--20s: %s"

    In [12]: print niceprint %('Process Real Memory Usage', pidMemoryInfo['rm'])
     Process Real Memory Usage: 12558336

    In [13]: print niceprint %('Process Virtual Memory Usage', pidMemoryInfo['vm'])
     Process Virtual Memory Usage: 97898496

    In [14]: pidCpuInfo = pr.getProcessCpuInfo(pid)

    In [15]: type pidCpuInfo
    -------> type(pidCpuInfo)
    Out[15]: <type 'dict'>

    In [16]: pidCpuInfo
    Out[16]: 
    {'css': datetime.timedelta(0, 0, 340000),
     'cus': datetime.timedelta(0, 0, 590000),
     'nice': 0L,
     'priority': 0L,
     'rcu': None}

    In [17]: print 'User: %s    System: %s' % (pidCpuInfo['cus'], pidCpuInfo['css'])
    User: 0:00:00.590000    System: 0:00:00.340000
    
    In [18]: print 'Nice: %s    Priority %s' % (pidCpuInfo['nice'], pidCpuInfo['priority'])
    Nice: 0    Priority 0

     
    """


    def getPids(self):
        """ Return ALL pids on system
        """
        pids = []
        for pid in enumprocess.getPids():
            pids.append(pid)

        return pids


    def getProcessObject(self, pid):
        """ Return PSI Process object from the pid number that you give
        as parameter.
        Ej: myprocess = process.getProcessObject(1234), then you can work with
        myprocess ...
        Arguments: pid
        """
        p = psi.process.Process(pid)

        return p

        
    def timedelta2seconds(self, d):
        return (d.days * 24*60*60 + d.seconds + d.microseconds*0.000001)

        
    def getProcessEnvironmentInfo(self, pid):
        """ Return pid environment info as dic{}
        Arguments: pid
        """
        p = self.getProcessObject(pid)
        environmentinfo = getattr(p, 'env', 'No Disponible')

        return environmentinfo

        
    def getProcessID(self, pid):
        """ Return pid number
        Arguments: pid
        """
        p = self.getProcessObject(pid)
        
        return p.pid

        
    def getProcessParentID(self, pid):
        """ Return parent process pid number
        Arguments: pid
        """
        p = self.getProcessObject(pid)
        
        return p.ppid

        
    def getProcessCommand(self, pid):
        """ Return process command name
        Arguments: pid
        """
        p = self.getProcessObject(pid)
        
        return p.command
        

    def getProcessRealUser(self, pid):
        """ Return process real user
        """
        p = self.getProcessObject(pid)
        realuser =  ('%s [%d]' % (pwd.getpwuid(p.ruid).pw_name,    \
                                                             p.ruid))

        return realuser
        
        
    def getProcessRealGroup(self, pid):
        """ Return process real group
        """
        p = self.getProcessObject(pid)
        realgroup = ('%s [%d]' % (grp.getgrgid(p.rgid).gr_name,    \
                                                            p.rgid))                                                                 
        
        return realgroup
        

    def getProcessEffectiveUser(self, pid):
        """ Return process effective user
        """
        p = self.getProcessObject(pid)
        effectiveuser = ('%s [%d]' % (pwd.getpwuid(p.euid).pw_name,    \
                                                                p.euid))

        return effectiveuser
        
        
    def getProcessEffectiveGroup(self, pid):
        """ Return process effective group
        Arguments: pid
        """
        p = self.getProcessObject(pid)
        effectivegroup = ('%s [%d]' % (grp.getgrgid(p.egid).gr_name,    \
                                                                    p.egid))
                                                                    
        return effectivegroup                                                                    
                                        

    def getProcessThreadsNumbers(self, pid):
        """ Return number of threads from process or None
        Arguments: pid
        """
        p = self.getProcessObject(pid)

        thr = getattr(p, 'nthreads', None)
        
        return thr
    
    
    def getProcessStartedDate(self, pid):
        """ Return date since the process was started or 'N/A'
        Arguments: pid
        """
        p = self.getProcessObject(pid)
        
        date = str(getattr(p, 'start_date', 'N/A'))
        
        return date
        

    def getProcessResidentMemoryUsage(self, pid):
        """ Return resident memory usage from pid process
        Arguments: pid
        """
        p = self.getProcessObject(pid)

        return p.rss


    def getProcessVirtualMemoryUsage(self, pid):
        """ Return virtual memory usage from pid process
        Arguments: pid
        """
        p = self.getProcessObject(pid)
        
        return p.vsz


    def getProcessCpuUserSpent(self, pid, time2secs = True):
        """ Return cpu time spent at the process by user
        Arguments: (pid, time2secs = True)
        If time2secs is set to False, ej:
        pr.getProcessCpuUserSpent(1234, False), then the time is returned
        as delta time, otherwise is returned as seconds (more human readable).
        """
        p = self.getProcessObject(pid)
        
        if time2secs != True:
            return p.utime
        else:
            return self.timedelta2seconds(p.utime)
            
            
    def getProcessCpuSystemSpent(self, pid, time2secs = True):
        """ Return cpu time spent at the process by system
        Arguments: (pid, time2secs = True)
        If time2secs is set to False, ej:
        pr.getProcessCpuUserSpent(1234, False), then the time is returned
        as delta time, otherwise is returned as seconds (more human readable).
        """
        p = self.getProcessObject(pid)
        
        if time2secs != True:
            return p.stime
        else:
            return self.timedelta2seconds(p.stime)
        

    def getProcessCpuNiceLevel(self, pid):
        """ Return nice lvl from the process or None
        Argument: pid
        """
        p = self.getProcessObject(pid)
        
        nice = getattr(p, 'nice', None)
        
        return nice
        

    def getProcessCpuPriority(self, pid):
        """ Return cpu priority from the process or None
        Argument: pid
        """
        p = self.getProcessObject(pid)
        
        priority = getattr(p, 'priority', None)
        
        return priority
        

    def printProcessGeneralInfo(self, pid):
        """ Format getProcessGeneralInfo and make it more friendly
        to read ...
        """
        p = self.getProcessObject(pid)
        pidinfo = enumprocess.processinfo.getPidDetails(pid)
        for key in pidinfo.keys():
            print '%s\t\t%s' % (key, pidinfo[key])


        print '-'*80 + '\n'
        
    def getProcessGeneralInfo(self, pid):
        """ Format getProcessGeneralInfo and make it more friendly
        to read ...
        """
        p = self.getProcessObject(pid)

        try:
            pidinfo = enumprocess.processinfo.getPidDetails(pid)
        except OSError, exc:
            sys.exit("Algo se cago feo ...\n" % ('pidinfo',
            exc.errno, exc.strerror))

        return pidinfo
